/*
 *  game.cpp
 *  @file this file contains the main entry for the game
 *  Created on: @date 18/01/2009
 *  @author: smaxll
 */

#include "SDL.h"
#include "SDL_opengl.h"
#include <ufo/ufo.hpp>
#include <ufo/ux/ux.hpp>

// This is for convenience.
// The UXSDLDriver provides a static function for
// SDL to UFO event conversion.
#include <ufo/ux/uxsdldriver.hpp>

#include "GL/gl.h"

#include "board.hpp"
#include "mouse_handler.hpp"
#include "game.hpp"

#include <cstdlib>
#include "stdio.h"
#include "stdlib.h"
#include <iostream>


namespace game_controller {

namespace {
    SDL_Surface *screen;
    unsigned screenW = 800;
    unsigned screenH = 600;

    bool gameStarted = false;

}
    chessPieceType currentPlayer = BLACK;

    void createContent(ufo::UWidget * content);
    void createContent2(ufo::UWidget * content);
    // menus are added to the root pane's menu bar
    void createMenu(ufo::URootPane * rootPane);

    void new_game(ufo::UActionEvent *e);
    void exit_ufo(ufo::UActionEvent * e);
    // this method is used as slot for a menu item
    void network_game(ufo::UActionEvent * e);
    void set_perferences(ufo::UActionEvent *e);

    int initScreen(){

        /** SDL initialization **/
        if ( SDL_Init(SDL_INIT_VIDEO) != 0 ) {
            printf("Unable to initialize SDL: %s\n", SDL_GetError());
            return 1;
        }

        // libUFO likes unicode values for key type events
        SDL_EnableUNICODE(1);

        // Enable key repeat
        SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY,
            SDL_DEFAULT_REPEAT_INTERVAL);

        /* Make sure SDL_QUIT get called when the program exit */
        atexit(SDL_Quit);

        // Set OpenGL attributes
        SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
        SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5);
        SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
        SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
        SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);

        // Create SDL frame
        screen = SDL_SetVideoMode( screenW, screenH, 16, SDL_OPENGL | SDL_HWSURFACE );

        if (screen == NULL) {
            fprintf(stderr, "Unable to set video mode to . %s\n", SDL_GetError());
            return false;
        }

        SDL_WM_SetCaption("Five in A row", NULL);


//        SDL_MapRGB(screen->format, 0xFF, 0x00, 0x00);

//        start_timer(60);
        return 0;
    }

    // Timer callback
//    Uint32 timer_callback(Uint32 interval, void *param) {
//        board::draw();
//        return 20;
//    }


    // Start a timer
//    void start_timer(int fps) {

        // Add a timer to run at 'fps' frames per second
//        SDL_AddTimer(20, timer_callback, 0);
//            printf("Error setting timer!\n%s", SDL_GetError());
//    }

    unsigned get_screen_width(){
        return screenW;
    }

    unsigned get_screen_height(){
        return screenH;
    }

    chessPieceType get_current_player(){
        return currentPlayer;
    }

    void loadscreen(){
        board::init();

        if(!board::draw()){
            std::cerr << "failed to draw the board" << std::endl;
        }

    }

    void set_camera(){

    }

    void playing(){
        // Init UFO
        ufo::UXToolkit tx;


        // Init the display with a dummy driver
        // Creates the UFO event queue and usually polls native events
        ufo::UXDisplay display("dummygl");

        // You must have a valid OpenGL context to create a UFO context.
        // The UFO context is responsible for UFO widgets and event processing
        ufo::UXContext context(
            // bounds of the OpenGL device
            ufo::URectangle(0, 0, 800, 600),
            // desired bounds of the UFO context (may differ from above values)
            ufo::URectangle(600, 0, 200, 600)
        );

        // a second context object
        /*
        ufo::UXContext context2(
                ufo::URectangle(0, 0, 800, 600),
                ufo::URectangle(650, 50, 100, 200)
        );
        */

        createContent(context.getRootPane()->getContentPane());
//        createContent2(context2.getRootPane()->getContentPane());

        // add the menu bar to the root pane
        createMenu(context.getRootPane());

        #define MAX_EVENTS 2
        static SDL_Event events[MAX_EVENTS];

        int numEvents = 0;

        // SDL event loop
        bool done = false;

        while (!done) {
            bool redraw = false;
            SDL_PumpEvents();
            // get SDL events from the event queue
            numEvents = SDL_PeepEvents(events, MAX_EVENTS, SDL_GETEVENT, 0xffffff);

            // this is for SDL event preprocessing
            for (int i = 0; i < numEvents; i++) {
                switch (events[i].type) {
                    case SDL_QUIT:
                        printf("Quit Five-in-a-row game. Bye!\n");
                        SDL_Quit();
                        exit(EXIT_SUCCESS);
                        break;
                    case SDL_KEYDOWN:
                    case SDL_KEYUP:
                        if (events[i].key.keysym.sym == SDLK_ESCAPE) {
                            // quit on escape
                            done = true;
                            SDL_Quit();
                            exit(EXIT_SUCCESS);
                        }
//                        std::cout << "SDL key event received\n";
                        break;
                    case SDL_MOUSEBUTTONDOWN:
                    case SDL_MOUSEBUTTONUP:
                        mouse_handler::mouse_down(&events[i]);
                        redraw = true;
//                        board::draw();
                        break;
                    case SDL_MOUSEMOTION:
    //                    std::cout << "SDL mouse motion event received\n";
                        break;
                    case SDL_VIDEORESIZE: {
                        // This resets internal SDL states and UFO device bounds
                        SDL_Surface * screen = SDL_GetVideoSurface();
                        SDL_SetVideoMode(events[i].resize.w, events[i].resize.h,
                            screen->format->BitsPerPixel, screen->flags);

                        // If your UFO context bounds depend on the frame size,
                        // you may change it here
                        // context.setContextBounds(URectangle(0, 0,
                        //  events[i].resize.w, events[i].resize.h));
                        }
                        break;
                    case SDL_VIDEOEXPOSE:
                        // mark the root pane to be repainted
                        redraw = true;
                        break;
                    default:
                        break;
                }
            }

            // Push all to the UFO event queue
            // This is a static method in the sdl device
            //  (usually only for internal use)
            ufo::UXSDLDriver::pushSDLEvents(
                events,  // array of events
                numEvents // event count
            );

            if (!done) {
                // dispatch events on the event queue
                // dispatchEvents return true when a quit was requested
                done = display.dispatchEvents();

//                if (context.needsRepaint() || context2.needsRepaint()) {
                if (context.needsRepaint()) {
//                    glClearColor(0.0f, 0.0f, 0.0f, 1.0f) ;
//                    glClear(GL_COLOR_BUFFER_BIT);
                    redraw = true;
                }

                // give other programs CPU time
                SDL_Delay(1);
            }

            if(redraw){
                // Set background color
                glClearColor(0.7, 0.6, 0.08, 0); /// Set up the backgroun color
                glClear(GL_COLOR_BUFFER_BIT); /// Clear the screen,

                // do your custom drawing here
                board::draw();

                // repaint the context
                context.repaint();
//                context2.repaint();

                glFlush();
                // swap opengl buffers
                SDL_GL_SwapBuffers();
                redraw = false;
            }


        }


        /** entering event loop */
        /*
        SDL_Event event;
        while (SDL_WaitEvent(&event) != 0) {
            switch(event.type){
            case SDL_QUIT:
                printf("Quit Five-in-a-row game. Bye!\n");
                exit(EXIT_SUCCESS);
                break;
            case SDL_MOUSEBUTTONDOWN:
                mouse_handler::mouse_down(&event);
            case SDL_MOUSEBUTTONUP:
                SDL_UpdateRect(screen, 0, 0, 0, 0);
                board::draw();
                break;
            case SDL_VIDEOEXPOSE:
                board::draw();
                break;

            }
        }
        */
    }

    void restart_game() {
        gameStarted = true;
    }

    void close_game() {
        gameStarted = false;
    }

    bool is_started(){
        return gameStarted;
    }

    void createContent(ufo::UWidget * content) {
        // we are using the flow layout as layout manager
        content->setLayout(new ufo::UFlowLayout());



    }

    void createContent2(ufo::UWidget * content) {
        // we are using the flow layout as layout manager
        content->setLayout(new ufo::UFlowLayout());

        // add a hello world label (static text)
        content->add(new ufo::ULabel("Hello, World!"));
        content->add(new ufo::UButton("button"));
    }

    void createMenu(ufo::URootPane * rootPane) {
        // first, we have to create a menu bar
        ufo::UMenuBar * mbar = new ufo::UMenuBar();

        // add the menu bar to the root pane
        rootPane->setMenuBar(mbar);

        // lets add some menus to the new menu bar
        ufo::UMenu * menu = new ufo::UMenu("&Game");

        // add the menu to the menu bar
        mbar->add(menu);

        ufo::UMenuItem * itemNewGame = new ufo::UMenuItem("&New Game");
        itemNewGame->sigActivated().connect(ufo::slot(&new_game));
        // a menu can have several menu items
        menu->add(itemNewGame);

        // you can connect the menu item with an slot
        // (see buttons.cpp and signals.cpp)

        ufo::UMenuItem * itemNetGame = new ufo::UMenuItem("Network &Game");
        itemNetGame->sigActivated().connect(ufo::slot(&network_game));
        menu->add(itemNetGame);

        // add a separator to the menu
        menu->addSeparator();

        ufo::UMenuItem * exit = new ufo::UMenuItem("quit");
        exit->sigActivated().connect(slot(&exit_ufo));
        menu->add(exit);

        menu->setEnabled(true);

        /// Second menu
        ufo::UMenu * menu2 = new ufo::UMenu("&Settings");
        mbar->add(menu2);

        ufo::UMenuItem *itemView = new ufo::UMenuItem("&View");
        itemView->setEnabled(false);
        menu2->add(itemView);

        // This sets the opacity hint used by the Look and feel.
        // Warning: experimental
        menu2->getPopupMenu()->setOpacity(0.7f);

        //
        // sub menus
        //
        // just add a menu to an existing menu and you have sub-menus

        menu2->addSeparator();

//        ufo::UMenu * submenu = new ufo::UMenu("sub-menu");
        // add it to the top-level menu
//        menu3->add(submenu);

//        UMenuItem * item2 = new UMenuItem("print blah 2");
//        submenu->add(item2);

        ufo::UMenuItem *itemPref = new ufo::UMenuItem("&Preferences");
        itemPref->sigActivated().connect(ufo::slot(&set_perferences));
        menu2->add(itemPref);

        /// Third menu
        ufo::UMenu *menu3 = new ufo::UMenu("&Help");
        mbar->add(menu3);



    }

    void new_game(ufo::UActionEvent *e){
        board::init();
    }

    void exit_ufo(ufo::UActionEvent * e) {
        // Send a quit event to the UFO event queue.
        // UDisplay::dispatchEvents() should return true.
        ufo::UDisplay::getDefault()->pushEvent(new ufo::UQuitEvent());
    }

    // this method is used as slot for a menu item
    void network_game(ufo::UActionEvent * e) {
        // If unspecified, the action command equals to the menu text
        // You can set the action command via
        //  {menu,button}->setActionCommand(string)
        // This way, you can easily connect multiple buttons to one
        // action slot.
        std::cout << "Network game started: " << e->getActionCommand() << "\n";
    }

    void set_perferences(ufo::UActionEvent *e){

    }
}

int main(int argc, char *argv[])
{

    game_controller::initScreen();
//    glClearColor( 0, 0, 0, 0 );

    glViewport( 0, 0, 600, 600 );

    glMatrixMode( GL_PROJECTION );
    glLoadIdentity();

    glOrtho( -1, 21.0, -1, 21.0, 1.0, -1.0 );

    glMatrixMode( GL_MODELVIEW );
    glLoadIdentity();

    game_controller::loadscreen();
    game_controller::playing();


    // Wait for 3 seconds to give us a chance to see the image
    SDL_Delay(3000);

    return 0;
}
